//! 日志事件结构模块
//!
//! 定义日志事件的数据结构，封装日志记录的所有信息。
//!
//! ## 主要类型
//!
//! - [`LogEvent`] - 日志事件结构体，包含级别、消息、时间戳等
//!
//! ## 示例
//!
//! ```rust
//! use log4r::{Level, LogEvent};
//!
//! let event = LogEvent::new(Level::Info, "my_app", "Hello, world!");
//! assert_eq!(event.level, Level::Info);
//! assert!(!event.is_fatal());
//! ```

use std::borrow::Cow;
use time::OffsetDateTime;

use crate::level::Level;

/// 日志事件结构体
///
/// 封装一条日志记录的所有信息，包括时间戳、级别、目标模块和消息内容。
///
/// ## 字段说明
///
/// - `timestamp` - 事件发生的时间戳
/// - `level` - 日志级别
/// - `target` - 目标模块路径
/// - `message` - 日志消息内容
/// - `write_to_syslog` - 是否需要写入系统日志（FATAL 级别自动设置为 true）
///
/// ## 线程安全
///
/// `LogEvent` 实现了 `Send + Sync`，可以安全地在线程间传递。
///
/// ## 示例
///
/// ```rust
/// use log4r::{Level, LogEvent};
///
/// // 创建普通日志事件
/// let info_event = LogEvent::new(Level::Info, "my_app::module", "操作完成");
/// assert!(!info_event.should_write_to_syslog());
///
/// // 创建 FATAL 级别事件（自动写入系统日志）
/// let fatal_event = LogEvent::new(Level::Fatal, "my_app", "严重错误");
/// assert!(fatal_event.is_fatal());
/// assert!(fatal_event.should_write_to_syslog());
/// ```
#[derive(Debug, Clone)]
pub struct LogEvent {
    /// 事件时间戳
    pub timestamp: OffsetDateTime,
    /// 日志级别
    pub level: Level,
    /// 目标模块路径
    pub target: Cow<'static, str>,
    /// 日志消息
    pub message: Cow<'static, str>,
    /// 是否需要写入系统日志（FATAL 级别自动设置为 true）
    pub write_to_syslog: bool,
}

// 编译时断言：验证 LogEvent 实现 Send + Sync
const _: () = {
    const fn assert_send_sync<T: Send + Sync>() {}
    assert_send_sync::<LogEvent>();
};

impl LogEvent {
    /// 创建新的日志事件
    ///
    /// 自动获取当前时间戳，优先使用本地时区，失败时降级到 UTC。
    /// FATAL 级别会自动设置 `write_to_syslog = true`。
    ///
    /// # Arguments
    ///
    /// * `level` - 日志级别
    /// * `target` - 目标模块路径
    /// * `message` - 日志消息
    ///
    /// # Examples
    ///
    /// ```rust
    /// use log4r::{Level, LogEvent};
    ///
    /// let event = LogEvent::new(Level::Info, "my_app", "Hello, world!");
    /// assert_eq!(event.level, Level::Info);
    /// assert!(!event.write_to_syslog);
    /// ```
    pub fn new(
        level: Level,
        target: impl Into<Cow<'static, str>>,
        message: impl Into<Cow<'static, str>>,
    ) -> Self {
        // 获取本地时间，失败时降级到 UTC
        let timestamp = OffsetDateTime::now_local().unwrap_or_else(|_| OffsetDateTime::now_utc());

        // FATAL 级别自动设置 write_to_syslog
        let write_to_syslog = level == Level::Fatal;

        Self {
            timestamp,
            level,
            target: target.into(),
            message: message.into(),
            write_to_syslog,
        }
    }

    /// 检查是否为 FATAL 级别
    ///
    /// # Examples
    ///
    /// ```rust
    /// use log4r::{Level, LogEvent};
    ///
    /// let fatal = LogEvent::new(Level::Fatal, "app", "error");
    /// assert!(fatal.is_fatal());
    ///
    /// let info = LogEvent::new(Level::Info, "app", "info");
    /// assert!(!info.is_fatal());
    /// ```
    #[inline]
    pub fn is_fatal(&self) -> bool {
        self.level == Level::Fatal
    }

    /// 检查是否需要写入系统日志
    ///
    /// # Examples
    ///
    /// ```rust
    /// use log4r::{Level, LogEvent};
    ///
    /// let fatal = LogEvent::new(Level::Fatal, "app", "error");
    /// assert!(fatal.should_write_to_syslog());
    ///
    /// let info = LogEvent::new(Level::Info, "app", "info");
    /// assert!(!info.should_write_to_syslog());
    /// ```
    #[inline]
    pub fn should_write_to_syslog(&self) -> bool {
        self.write_to_syslog
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
    use super::*;
    use time::OffsetDateTime;

    // UT-2.2-001: 测试 LogEvent 字段正确性
    #[test]
    fn test_logevent_new_creates_event_with_correct_fields() {
        // GIVEN: 日志级别、目标和消息
        let level = Level::Info;
        let target = "my_app::module";
        let message = "测试消息";

        // WHEN: 创建 LogEvent
        let event = LogEvent::new(level, target, message);

        // THEN: 所有字段应正确设置
        assert_eq!(event.level, Level::Info);
        assert_eq!(event.target, "my_app::module");
        assert_eq!(event.message, "测试消息");
        assert!(!event.write_to_syslog);
    }

    // UT-2.2-002: 测试 FATAL 级别自动设置 write_to_syslog = true
    #[test]
    fn test_fatal_level_sets_write_to_syslog_true() {
        // GIVEN: FATAL 级别
        let level = Level::Fatal;

        // WHEN: 创建 LogEvent
        let event = LogEvent::new(level, "app", "fatal error");

        // THEN: write_to_syslog 应为 true
        assert!(event.write_to_syslog);
        assert!(event.is_fatal());
        assert!(event.should_write_to_syslog());
    }

    // UT-2.2-002b: 测试非 FATAL 级别 write_to_syslog = false
    #[test]
    fn test_non_fatal_levels_set_write_to_syslog_false() {
        // GIVEN: 所有非 FATAL 级别
        let non_fatal_levels = [
            Level::Trace,
            Level::Debug,
            Level::Info,
            Level::Warn,
            Level::Error,
        ];

        for level in non_fatal_levels {
            // WHEN: 创建 LogEvent
            let event = LogEvent::new(level, "app", "message");

            // THEN: write_to_syslog 应为 false
            assert!(
                !event.write_to_syslog,
                "{:?} 级别不应设置 write_to_syslog",
                level
            );
            assert!(!event.is_fatal());
            assert!(!event.should_write_to_syslog());
        }
    }

    // UT-2.2-003: 编译时验证 LogEvent 实现 Send + Sync
    #[test]
    fn test_logevent_is_send_sync() {
        // GIVEN/WHEN: 编译时断言函数
        fn assert_send<T: Send>() {}
        fn assert_sync<T: Sync>() {}

        // THEN: LogEvent 应实现 Send + Sync（编译通过即验证成功）
        assert_send::<LogEvent>();
        assert_sync::<LogEvent>();
    }

    // UT-2.2-004: 测试时间戳在合理范围内
    #[test]
    fn test_timestamp_is_within_reasonable_range() {
        // GIVEN: 记录创建前的时间
        let before = OffsetDateTime::now_utc();

        // WHEN: 创建 LogEvent
        let event = LogEvent::new(Level::Info, "app", "message");

        // THEN: 时间戳应在 before 和 after 之间
        let after = OffsetDateTime::now_utc();

        // 转换为 UTC 进行比较（避免时区问题）
        let event_utc = event.timestamp.to_offset(time::UtcOffset::UTC);
        assert!(event_utc >= before, "时间戳应 >= 创建前时间");
        assert!(event_utc <= after, "时间戳应 <= 创建后时间");
    }

    // UT-2.2-005: 测试时区降级 - 时间戳获取不会 panic
    #[test]
    fn test_timestamp_acquisition_does_not_panic() {
        // GIVEN/WHEN: 多次创建 LogEvent
        // THEN: 不应 panic（时区获取失败时降级到 UTC）
        for _ in 0..10 {
            let event = LogEvent::new(Level::Info, "app", "message");
            // 验证时间戳有效（年份在合理范围内）
            assert!(event.timestamp.year() >= 2020);
            assert!(event.timestamp.year() <= 2100);
        }
    }

    // 测试 is_fatal() 方法
    #[test]
    fn test_is_fatal_method() {
        // GIVEN: FATAL 和非 FATAL 事件
        let fatal = LogEvent::new(Level::Fatal, "app", "fatal");
        let error = LogEvent::new(Level::Error, "app", "error");

        // WHEN/THEN: is_fatal() 返回正确结果
        assert!(fatal.is_fatal());
        assert!(!error.is_fatal());
    }

    // 测试 Cow 字符串的静态和动态使用
    #[test]
    fn test_cow_string_static_and_dynamic() {
        // GIVEN: 静态字符串
        let event_static = LogEvent::new(Level::Info, "static_target", "static_message");

        // GIVEN: 动态字符串
        let dynamic_target = format!("dynamic_{}", "target");
        let dynamic_message = format!("dynamic_{}", "message");
        let event_dynamic = LogEvent::new(Level::Info, dynamic_target, dynamic_message);

        // THEN: 两种方式都应正常工作
        assert_eq!(event_static.target, "static_target");
        assert_eq!(event_dynamic.target, "dynamic_target");
    }

    // UT-2.2-006: 测试 LogEvent Clone trait
    #[test]
    fn test_logevent_clone() {
        // GIVEN: 一个 LogEvent 实例
        let original = LogEvent::new(Level::Error, "clone_test", "clone message");

        // WHEN: 克隆事件
        let cloned = original.clone();

        // THEN: 克隆应与原始相等
        assert_eq!(cloned.level, original.level);
        assert_eq!(cloned.target, original.target);
        assert_eq!(cloned.message, original.message);
        assert_eq!(cloned.write_to_syslog, original.write_to_syslog);
        // 时间戳也应相等
        assert_eq!(cloned.timestamp, original.timestamp);
    }

    // UT-2.2-007: 测试 LogEvent Debug trait
    #[test]
    fn test_logevent_debug() {
        // GIVEN: 一个 LogEvent 实例
        let event = LogEvent::new(Level::Warn, "debug_test", "debug message");

        // WHEN: 格式化为 Debug 字符串
        let debug_str = format!("{:?}", event);

        // THEN: 应包含所有字段信息
        assert!(debug_str.contains("LogEvent"), "应包含类型名");
        assert!(debug_str.contains("Warn"), "应包含级别");
        assert!(debug_str.contains("debug_test"), "应包含 target");
        assert!(debug_str.contains("debug message"), "应包含消息");
    }

    // UT-2.2-008: 测试直接构造 LogEvent（覆盖字段访问）
    #[test]
    fn test_logevent_direct_field_access() {
        use time::{Date, Month, PrimitiveDateTime, Time, UtcOffset};

        // GIVEN: 手动构造的时间戳
        let date = Date::from_calendar_date(2025, Month::June, 15).unwrap();
        let time = Time::from_hms(10, 30, 45).unwrap();
        let datetime = PrimitiveDateTime::new(date, time);
        let timestamp = datetime.assume_offset(UtcOffset::UTC);

        // WHEN: 直接构造 LogEvent
        let event = LogEvent {
            timestamp,
            level: Level::Debug,
            target: Cow::Borrowed("direct_test"),
            message: Cow::Owned("owned message".to_string()),
            write_to_syslog: false,
        };

        // THEN: 所有字段应正确
        assert_eq!(event.level, Level::Debug);
        assert_eq!(event.target, "direct_test");
        assert_eq!(event.message, "owned message");
        assert!(!event.write_to_syslog);
        assert!(!event.is_fatal());
        assert!(!event.should_write_to_syslog());
    }

    // UT-2.2-009: 测试 FATAL 事件直接构造
    #[test]
    fn test_logevent_fatal_direct_construction() {
        // GIVEN: 直接构造 FATAL 事件，手动设置 write_to_syslog
        let event = LogEvent {
            timestamp: OffsetDateTime::now_utc(),
            level: Level::Fatal,
            target: Cow::Borrowed("fatal_direct"),
            message: Cow::Borrowed("fatal error"),
            write_to_syslog: true,
        };

        // THEN: 应正确识别为 FATAL
        assert!(event.is_fatal());
        assert!(event.should_write_to_syslog());
    }

    // UT-2.2-010: 测试空字符串消息
    #[test]
    fn test_logevent_empty_message() {
        // GIVEN: 空消息
        let event = LogEvent::new(Level::Info, "empty_test", "");

        // THEN: 应正常创建
        assert_eq!(event.message, "");
        assert_eq!(event.target, "empty_test");
    }

    // UT-2.2-011: 测试空 target
    #[test]
    fn test_logevent_empty_target() {
        // GIVEN: 空 target
        let event = LogEvent::new(Level::Info, "", "message");

        // THEN: 应正常创建
        assert_eq!(event.target, "");
        assert_eq!(event.message, "message");
    }

    // UT-2.2-012: 测试 Unicode 内容
    #[test]
    fn test_logevent_unicode_content() {
        // GIVEN: Unicode 内容
        let event = LogEvent::new(Level::Info, "日志::模块", "消息 🚀 émoji テスト العربية");

        // THEN: Unicode 应正确保存
        assert_eq!(event.target, "日志::模块");
        assert!(event.message.contains("🚀"));
    }
}
